package com.general.config;

import org.eclipse.microprofile.config.spi.ConfigSource;

import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * @description: MutableConfigSources
 * @author: general
 * @version: 1.0
 * @create: 2021-10-27 21:03
 **/
public class MutableConfigSources implements ConfigSources {

    private final List<ConfigSource> configSourceList = new CopyOnWriteArrayList<>();

    public MutableConfigSources() {
    }

    public MutableConfigSources(ConfigSources configSources){
        this();
        for (ConfigSource propertySource : configSources) {
            addLast(propertySource);
        }
    }

    public void addFirst(ConfigSource propertySource) {
        removeIfPresent(propertySource);
        this.configSourceList.add(0, propertySource);
    }

    public void addLast(ConfigSource propertySource) {
        removeIfPresent(propertySource);
        this.configSourceList.add(propertySource);
    }

    protected void removeIfPresent(ConfigSource configSource) {
        this.configSourceList.remove(configSource);
    }

    public void addBefore(String relativePropertySourceName, ConfigSource configSource) {
        assertLegalRelativeAddition(relativePropertySourceName, configSource);
        removeIfPresent(configSource);
        int index = assertPresentAndGetIndex(relativePropertySourceName);
        addAtIndex(index, configSource);
    }

    protected void assertLegalRelativeAddition(String relativeConfigSourceName, ConfigSource configSource) {
        String newPropertySourceName = configSource.getName();
        if (relativeConfigSourceName.equals(newPropertySourceName)) {
            throw new IllegalArgumentException(
                    "PropertySource named '" + newPropertySourceName + "' cannot be added relative to itself");
        }
    }

    private int assertPresentAndGetIndex(String name) {
        int index = 0, find = -1;
        for(ConfigSource configSource: configSourceList){
            if(configSource.getName().equals(name)){
                find = 1;
                return index;
            }
            index++;
        }

        if (find == -1) {
            throw new IllegalArgumentException("PropertySource named '" + name + "' does not exist");
        }
        return index;
    }

    private void addAtIndex(int index, ConfigSource configSource) {
        removeIfPresent(configSource);
        this.configSourceList.add(index, configSource);
    }

    @Override
    public boolean contains(String name) {
        return this.configSourceList.stream().anyMatch(each->each.getName().equals(name));
    }

    @Override
    public ConfigSource get(String name) {
        return this.configSourceList.stream().filter(each->each.getName().equals(name)).findFirst().get();
    }

    @Override
    public Iterator<ConfigSource> iterator() {
        return this.configSourceList.iterator();
    }

    @Override
    public String toString() {
        return "MutableConfigSources{" +
                "configSourceList=" + configSourceList +
                '}';
    }
}
